import java.io.*;
import java.net.*;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import sun.security.rsa.RSAPublicKeyImpl;

/**
 *
 * @author Alexandre
 * @author Lucas
 */
public class Cliente {
    
    static PublicKey chavePub;
    static int PORTA = 5000;
    static String hostIP = "127.0.0.1"; //ou localhost

    /**
     * @param args
     * @throws java.security.NoSuchAlgorithmException
     * @throws javax.crypto.NoSuchPaddingException
     * @throws java.net.SocketException
     * @throws java.net.UnknownHostException
     * @throws javax.crypto.IllegalBlockSizeException
     * @throws javax.crypto.BadPaddingException
     * @throws java.security.InvalidKeyException
     * @throws java.security.SignatureException
     */
    public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, SocketException, UnknownHostException, IOException, IllegalBlockSizeException, BadPaddingException, InvalidKeyException, SignatureException {
        System.out.println("Cliente executando");
        //Passo 1: Obter a instância
        Cipher cifra = Cipher.getInstance("RSA");

        //Socket UDP
        DatagramSocket socketUDP = new DatagramSocket();
        InetAddress IPServidor = InetAddress.getByName(hostIP);
        
        BufferedReader entradaUsuario
                = new BufferedReader(
                        new InputStreamReader(System.in));
        
        String msg;
        DatagramPacket datagrama;
        byte[] chavePublica;
        
        while (true) {
            msg = entradaUsuario.readLine();
            byte[] msgEnvio = msg.getBytes();
            
            if (msg.equals("exit")) {

                //datagrama UDP (pacote) de envio
                datagrama = new DatagramPacket(msg.getBytes(), msg.getBytes().length, IPServidor, PORTA);
                
                socketUDP.send(datagrama);
                
                socketUDP.close();
                break;
            } else {
                if (msg.equals("iniciar")) {

                    //datagrama UDP (pacote) de envio
                    datagrama = new DatagramPacket(msg.getBytes(), msg.getBytes().length, IPServidor, PORTA);
                    
                    socketUDP.send(datagrama);
                    
                    byte[] bufferResposta = new byte[1025];

                    //Datagrama UDP a ser recebido
                    DatagramPacket datagramaResposta = new DatagramPacket(bufferResposta, bufferResposta.length);
                    socketUDP.receive(datagramaResposta);
                    System.out.println("Chave Pública recebida");
                    chavePublica = bufferResposta;
                    chavePub = new RSAPublicKeyImpl(chavePublica);
                    cifra.init(Cipher.ENCRYPT_MODE, chavePub);
                    
                } else {
                    if (msg.equals("assinatura")) {
                        datagrama = new DatagramPacket(msg.getBytes(), msg.getBytes().length, IPServidor, PORTA);
                        
                        socketUDP.send(datagrama);
                        
                        byte[] bufferResposta = new byte[64];

                        //Datagrama UDP a ser recebido
                        DatagramPacket datagramaResposta = new DatagramPacket(bufferResposta, bufferResposta.length);
                        socketUDP.receive(datagramaResposta);

                        /**
                         * Recebendo o texto claro
                         */
                        byte[] bufferTextoClaro = bufferResposta;
                        String auxMsgAss = new String(bufferResposta);
                        auxMsgAss = auxMsgAss.trim();
                        System.out.println("Mensagem da assinatura recebida");
                        
                        /**
                         * Recebe a assinatura
                         */
                        socketUDP.receive(datagramaResposta);
                        byte[] bufferSgnature = bufferResposta;
                        System.out.println("Assinatura recebida");
                        /**
                         * Validando a assinatura
                         */
                        Signature clientSig = Signature.getInstance("SHA1withRSA");
                        clientSig.initVerify(chavePub);
                        clientSig.update(auxMsgAss.getBytes());
                        
                        if (clientSig.verify(bufferSgnature)) {
                            System.out.println("Mensagem assinada corretamente!");
                        } else {
                            System.out.println("Assinatura deu ruim!");
                        }
                        
                    } else {
                        //Passo 3: cifragem
                        byte[] TEXTO_CIFRADO = cifra.doFinal(msg.getBytes());
                        datagrama = new DatagramPacket(TEXTO_CIFRADO, TEXTO_CIFRADO.length, IPServidor, PORTA);
                        socketUDP.send(datagrama);
                    }
                }
            }
        }
    }
}
